import java.awt.BorderLayout;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

import javax.swing.ButtonGroup;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JRadioButtonMenuItem;

public class MainClass implements ActionListener{

	public static void main(String[] args){
	
		new MainClass();
	
	}
	Lock lock;
	JFrame frame;
	JMenuItem newgame,exit,restartItem;
	JMenuItem loadDefaultMapItemUpper,loadDefaultMapItemLower,loadDefaultMapItem,loadDefaultMapWithNoPolice;
	JMenuItem policeItem,racerItem,obstacleItem,targetItem,startItem,pauseItem,hideplaceItem,resumeItem,polStation,emptyItem;

	JRadioButtonMenuItem size12,size18,size24;
	MainPanel mainpanel;
	Configuration configuration;
	JMenu addComponent;
	int componentPanelSize;
	Statistic statisticPanel; 
	JPanel p;
	public MainClass() {
		componentPanelSize = 12;	// default panel size
		frame = new JFrame("NeFiS");
		frame.setLayout(new BorderLayout(0,0));
		lock = new ReentrantLock();
		statisticPanel = new Statistic();
		p = new JPanel(new GridLayout(2,1));
		mainpanel= new MainPanel(componentPanelSize,lock,statisticPanel,p);
		configuration = new Configuration(mainpanel);
		
		
		//initialize menu bar and its menu items
		JMenuBar jmb = new JMenuBar();
		JMenu file = new JMenu("File");
		addComponent = new JMenu("Add");
		JMenu run = new JMenu("Run");
		JMenu settings = new JMenu("Settings");
		JMenu boardSize = new JMenu("Board Size");
		
		polStation = new JMenuItem("PoliceStation");
		newgame = new JMenuItem("New game");
		exit = new JMenuItem("Exit");
	    policeItem = new JMenuItem("Police");
	    racerItem = new JMenuItem("Racer");
	    obstacleItem =  new JMenuItem("Obstacle");
	    targetItem =  new JMenuItem("Target");
	    startItem = new JMenuItem("Start");
	    pauseItem =  new JMenuItem("Pause");
	    resumeItem = new JMenuItem("Resume");
	    hideplaceItem = new JMenuItem("Hide Place");
	    emptyItem = new JMenuItem("Road");
	    restartItem = new JMenuItem("Restart");
	    loadDefaultMapItemUpper = new JMenuItem("Load Default Map Upper Hidden");
	    loadDefaultMapItemLower = new JMenuItem("Load Default Map Lower Hidden");
	    loadDefaultMapItem = new JMenuItem("Load Default Map");
	    loadDefaultMapWithNoPolice = new JMenuItem("Load Default Map With No Police");
	    //add action listeners to menu items
		newgame.addActionListener(this);
		exit.addActionListener(this);
		policeItem.addActionListener(this);
		racerItem.addActionListener(this);
		obstacleItem.addActionListener(this);
		targetItem.addActionListener(this);
		startItem.addActionListener(this);
		pauseItem.addActionListener(this);
		resumeItem.addActionListener(this);
		hideplaceItem.addActionListener(this);
		polStation.addActionListener(this);
		emptyItem.addActionListener(this);
		restartItem.addActionListener(this);
		loadDefaultMapItemUpper.addActionListener(this);
		loadDefaultMapItemLower.addActionListener(this);
		loadDefaultMapItem.addActionListener(this);
		loadDefaultMapWithNoPolice.addActionListener(this);
		
		file.add(newgame);
		file.add(exit);
		//file.add(statisticItem);
		
		addComponent.add(policeItem);
		addComponent.add(racerItem);
		addComponent.add(obstacleItem);
		addComponent.add(targetItem);
		addComponent.add(hideplaceItem);
		addComponent.add(polStation);
		addComponent.add(emptyItem);
		
		run.add(startItem);
		run.add(pauseItem);
		run.add(resumeItem);
		run.add(restartItem);
		
		size12 = new JRadioButtonMenuItem("12 x 12");
		size18 = new JRadioButtonMenuItem("18 x 18");
		size24 = new JRadioButtonMenuItem("24 x 24");
		
		size12.addActionListener(this);
		size18.addActionListener(this);
		size24.addActionListener(this);
		
		size12.setSelected(true);
		
		ButtonGroup group = new ButtonGroup();
		group.add(size12);
		group.add(size18);
		group.add(size24);
		
		boardSize.add(size12);
		boardSize.add(size18);
		boardSize.add(size24);
		
		settings.add(boardSize);
		settings.add(loadDefaultMapItemUpper);
		settings.add(loadDefaultMapItemLower);
		settings.add(loadDefaultMapItem);
		settings.add(loadDefaultMapWithNoPolice);
		
		jmb.add(file);
		jmb.add(addComponent);
		jmb.add(run);
		jmb.add(settings);
		
		//construct frame
		frame.add(jmb,BorderLayout.NORTH);
		frame.add(mainpanel,BorderLayout.CENTER);
		
		p.add(configuration);
		p.add(statisticPanel);
		frame.add(p,BorderLayout.EAST);
		
		frame.setIconImage(new ImageIcon("picture/nefis.png").getImage()) ;
		frame.pack();
	    frame.setSize(900,750);
		frame.setLocationRelativeTo(null);
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		frame.setVisible(true);
		frame.setResizable(false);
			
	}
	@SuppressWarnings("static-access")
	//this method kills all mainpanel threads
	public void stopAllThreads(){
		mainpanel.stopComponent();
	}
	
	@SuppressWarnings({ "static-access", "deprecation" })
	public void actionPerformed(ActionEvent arg0) {
	
		if(arg0.getSource()==newgame){
			initComponents(componentPanelSize);
		}
		
		else if(arg0.getSource()==exit){
			System.exit(0);
		}
		else if(arg0.getSource()==loadDefaultMapItemUpper){
			initComponents(componentPanelSize);
			mainpanel.loadDefaultMapUpper();
		}
		else if(arg0.getSource()==loadDefaultMapItemLower){
			initComponents(componentPanelSize);
			mainpanel.loadDefaultMapLower();
		}
		else if(arg0.getSource()==loadDefaultMapItem){
			initComponents(componentPanelSize);
			mainpanel.loadDefaultMap();
		}
		else if(arg0.getSource()==loadDefaultMapWithNoPolice){
			initComponents(componentPanelSize);
			mainpanel.loadDefaultMapWithNoPolice();
		}
		else if(arg0.getSource()==emptyItem){
			mainpanel.component = new Empty();
		}
		
		else if(arg0.getSource()==policeItem){
			
			mainpanel.component = new Police(componentPanelSize,0);
		}
		
		else if(arg0.getSource()==racerItem){
			
			mainpanel.component = new Racer(componentPanelSize,0);

		}
		else if(arg0.getSource()==polStation){
			mainpanel.component = new PoliceStation(componentPanelSize);
		}	
		else if(arg0.getSource()==obstacleItem){
			
			mainpanel.component = new Obstacle();
		}
		
		else if(arg0.getSource()==targetItem){

        	mainpanel.component = new Target();

        }
        
		else if(arg0.getSource()==hideplaceItem){

			mainpanel.component = null;
			
		}
        
		else if(arg0.getSource()==startItem){
			//get the number of episodes from user and remove mouse listeners from mainpanel 
			//and start agents
        	do{
        		try{
        			int episode=Integer.parseInt(JOptionPane.showInputDialog("Please Enter An Episode Number"));
        			Component.EPISODE = episode;
        			if(episode>0)
        				break;
        		}catch(Exception e){
        			
        		}
        	}while(true);
        	mainpanel.removeMouseListeners();
        	mainpanel.moveComponent();
        	startItem.setEnabled(false);
        	addComponent.setEnabled(false);
        }
		//starts agents from the beginning
		else if(arg0.getSource()==restartItem){
        	for(int i = 0;i<3;i++){
        		
        		if(mainpanel.racer[i]!=null){
        			//lock.lock();
        			mainpanel.threadRacer[i].stop();
        			mainpanel.componentpanel[mainpanel.racer[i].currentState.x][mainpanel.racer[i].currentState.y].component = new Empty();
    				mainpanel.componentpanel[mainpanel.racer[i].currentState.x][mainpanel.racer[i].currentState.y].putComponent(new Empty().getImage());
        			State s = new State(mainpanel.racer[i].initialState.x,mainpanel.racer[i].initialState.y);
        		
        			mainpanel.racer[i] = new Racer(componentPanelSize,mainpanel.racer[i].componentNum-1);
        			mainpanel.racer[i].initialState = new State(s.x,s.y);
        			mainpanel.racer[i].currentState = new State(s.x,s.y);
        			lock = new ReentrantLock();
        			mainpanel.lock = lock; 
        			mainpanel.threadRacer[i] = new Thread(new MoveRacer(mainpanel.racer[i],mainpanel.componentpanel,componentPanelSize,lock,statisticPanel,p));
        			mainpanel.racer[i].temporal = new DynaQ(mainpanel.temporal.alpha,mainpanel.temporal.gamma,mainpanel.temporal.epsilon,0,10); 
        			mainpanel.racer[i].temporal.reward = 0;
        			mainpanel.racer[i].counter = 0;
        			mainpanel.racer[i].total = 0;
        			mainpanel.racer[i].episode = 1;
        			mainpanel.threadRacer[i].start();
        		}
        		if(mainpanel.police[i]!=null){
        			//lock.lock();
        			mainpanel.threadPolice[i].stop();
        			mainpanel.componentpanel[mainpanel.police[i].currentState.x][mainpanel.police[i].currentState.y].component = new Empty();
    				mainpanel.componentpanel[mainpanel.police[i].currentState.x][mainpanel.police[i].currentState.y].putComponent(new Empty().getImage());
        			State s = new State( mainpanel.police[i].initialState.x, mainpanel.police[i].initialState.y);
        		
        			mainpanel.componentpanel[mainpanel.police[i].currentState.x][mainpanel.police[i].currentState.y].isNextPolice = false;
        			mainpanel.componentpanel[mainpanel.police[i].nextState.x][mainpanel.police[i].nextState.y].isNextPolice = false;
        			
        			mainpanel.police[i] = new Police(componentPanelSize,mainpanel.police[i].componentNum-1);
        			mainpanel.police[i].initialState = new State(s.x,s.y);
        			mainpanel.police[i].currentState = new State(s.x,s.y);
        			mainpanel.componentpanel[mainpanel.police[i].currentState.x][mainpanel.police[i].currentState.y].isNextPolice = true;
        			lock = new ReentrantLock();
        			mainpanel.lock = lock; 
        			mainpanel.threadPolice[i] = new Thread(new MovePolice(mainpanel.police[i],mainpanel.componentpanel,componentPanelSize,lock,mainpanel.polStation));
        			mainpanel.polStation.temporal.reward = 0;
        			mainpanel.police[i].counter = 0;
        			mainpanel.police[i].total = 0;
        			mainpanel.police[i].episode = 1;
        			mainpanel.threadPolice[i].start();
        		}
        		
        	}
        	//cleaning agent's qvalues means cleaning their memory
        	//mainpanel.resetQValues();
        }
		//pause mainpanel's agents
		else if(arg0.getSource()==pauseItem){
        	mainpanel.pauseComponent();
        	addComponent.setEnabled(true);
        	mainpanel.addMouseListeners();
        }
        //resumes mainpanel's agent
		else if(arg0.getSource()==resumeItem){
        	mainpanel.resumeComponent();
        	addComponent.setEnabled(false);
        	mainpanel.removeMouseListeners();
        }
        
        //initialize table with specified size
		else if(arg0.getSource()==size12){
        	initComponents(12);
        }
        
		else if(arg0.getSource()==size18){
        	initComponents(18);
        }
        
		else if(arg0.getSource()==size24){
        	initComponents(24);
        }
	}
	//initializes mainpanel
	public void initComponents(int tableSize){
		stopAllThreads();
    	frame.remove(mainpanel);
    	lock = new ReentrantLock();
		mainpanel = new MainPanel(tableSize,lock,statisticPanel,p);
		componentPanelSize = tableSize;
		configuration = new Configuration(mainpanel);
		frame.add(mainpanel,BorderLayout.CENTER);
		frame.setVisible(true);
		startItem.setEnabled(true);
		addComponent.setEnabled(true);
	}
}
